#pragma once
#include <memory>
#include <mutex>
#include <unordered_map>
#include <cstdio>
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/TcpConnection.h>
#include <muduo/net/Buffer.h>
#include <muduo/base/CountDownLatch.h>
#include <muduo/net/EventLoopThread.h>
#include <muduo/net/TcpClient.h>
#include "abstract.hpp"
#include "detail.hpp"
#include "fields.hpp"
#include "message.hpp"

namespace rpc
{
    //实现缓冲区
    class MuduoBuffer : public BaseBuffer
    {
    public:
        using ptr = std::shared_ptr<MuduoBuffer>;
        MuduoBuffer(muduo::net::Buffer *buf) : _buf(buf)
        {
        }
        //直接调用muduo库对应的接口
        virtual size_t readableSize() override //缓冲区可读数据大小
        {
            return _buf->readableBytes();
        }

        virtual int32_t PeekInt32() override //尝试获取四字节数据
        {
            //muduo库从缓冲区取出一个4字节整形,会进行网络字节序的转换,转换为主机字节序
            return _buf->peekInt32();
        }

        virtual void retrieveInt32() override //删除缓冲区前四字节数据
        {
            return _buf->retrieveInt32();
        }

        virtual int32_t readInt32() override //PeekInt32()+retrieveInt32()
        {
            return _buf->readInt32();
        }

        virtual std::string retrieveAsString(size_t len) override //取出指定长度的字符串
        {
            return _buf->retrieveAsString(len);
        }

    private:
        //不需要自己释放
        muduo::net::Buffer *_buf;//基于muduo库的buff对象
    };

    //生产缓冲区的工厂模式
    class BufferFactory
    {
    public:
        template <typename... Args>
        static BaseBuffer::ptr create(Args &&...args)
        {
            return std::make_shared<MuduoBuffer>(std::forward<Args>(args)...);
        }
    };

    //协议的实现
    class LVProtocol : public BaseProtocol
    {
        // |--Len--|--mtype--|--idlen--|--id--|--body--|
    public:
        using ptr = std::shared_ptr<LVProtocol>;
        virtual bool canProcessed(const BaseBuffer::ptr &buf) override  //判断缓冲区的数据量是否能够处理一条消息
        {
            if (buf->readableSize() < lenFieldsLength)
            {
                return false;
            }
            int32_t total_len = buf->PeekInt32();//total_len不算上len的长度
            if (buf->readableSize() < total_len + lenFieldsLength)
            {
                return false;
            }
            return true;
        }

        //调用onMessage的时候,认为缓冲区足够一条完整的消息
        virtual bool onMessage(const BaseBuffer::ptr &buf, BaseMessage::ptr &msg) override  //读取缓冲区的内容到一个消息对象中
        {
            int32_t total_len = buf->readInt32();//取出len->总长度
            MType mtype = (MType)buf->readInt32();//取出Mtype
            int32_t idlen = buf->readInt32();//取出idlen
            int32_t body_len = total_len - idlenFieldsLength - mtypeFieldsLength - idlen;//取出body的长度
            std::string id = buf->retrieveAsString(idlen);//读取id
            std::string body = buf->retrieveAsString(body_len);//读取body
            msg = MessageFactory::create(mtype);//返回这个消息对象给外面
            if (msg.get() == nullptr)
            {
                LOG(ERROR, "消息类型错误,构造消息对象失败");
                return false;
            }
            bool ret = msg->unserialize(body);//反序列化
            if (ret == false)
            {
                LOG(ERROR, "消息正文反序列化失败");
                return false;
            }
            msg->setId(id);
            msg->setMType(mtype);
            return true;
        }

        virtual std::string serialize(const BaseMessage::ptr &msg) override  //序列化消息
        {
            std::string body = msg->serialize();//信息
            std::string id = msg->rid();//id
            auto mtype = htonl((int32_t)msg->mtype());//网络序列的类型
            int32_t h_idlen = id.size();//id长度
            int32_t n_idlen = htonl(h_idlen);//id长度网络序列
            int32_t h_total_len = mtypeFieldsLength + idlenFieldsLength + h_idlen + body.size();//总长度
            int32_t n_total_len = htonl(h_total_len);//总长度主机序列
            std::string result;
            result.reserve(h_total_len+lenFieldsLength);//开辟空间
            result.append((char *)&n_total_len, lenFieldsLength);
            result.append((char *)&mtype, mtypeFieldsLength);
            result.append((char *)&n_idlen, idlenFieldsLength);
            result.append(id);
            result.append(body);
            return result;
        }
    private:
        const size_t lenFieldsLength = 4; //len 所需长度为4
        const size_t mtypeFieldsLength = 4;//消息类型为4的长度
        const size_t idlenFieldsLength = 4;//存储uuid的长度的字段的长度为4
    };

    class ProtocolFactory
    {
    public:
        template <typename... Args>
        static BaseProtocol::ptr create(Args &&...args)
        {
            return std::make_shared<LVProtocol>(std::forward<Args>(args)...);
        }
    };

    //连接对象
    class MuduoConnection : public BaseConnection
    {
    public:
        MuduoConnection(const muduo::net::TcpConnectionPtr &conn, const BaseProtocol::ptr &protocol)
            : _protocol(protocol), _conn(conn) {}
        using ptr = std::shared_ptr<MuduoConnection>;
        virtual void send(const BaseMessage::ptr &msg) override //发送消息
        {
            std::string body = _protocol->serialize(msg);//序列化
            _conn->send(body);//发送消息
        }

        virtual void shutdown() override //关闭连接
        {
            _conn->shutdown();
        }

        virtual bool connected() override //判断连接是否正常
        {
            return _conn->connected();
        }

    private:
        BaseProtocol::ptr _protocol;//协议对象
        muduo::net::TcpConnectionPtr _conn;//连接对象
    };

    class ConnectionFactory
    {
    public:
        template <typename... Args>
        static BaseConnection::ptr create(Args &&...args)
        {
            return std::make_shared<MuduoConnection>(std::forward<Args>(args)...);
        }
    };

    //服务端
    class MuduoServer : public BaseServer
    {
    private:
        // 客户端建立连接成功/连接关闭成功的回调
        void onConnection(const muduo::net::TcpConnectionPtr &conn)
        {
            if (conn->connected())//建立连接
            {
                LOG(INFO, "连接建立");
                BaseConnection::ptr muduo_conn = ConnectionFactory::create(conn, _protocol);//传入muduo库创建的链接+自定义协议
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    _conns.insert(std::make_pair(conn, muduo_conn));
                }
                if (_cb_connection) //检测是否设置了回调函数->父类已经实现
                    _cb_connection(muduo_conn);
            }
            else
            {
                LOG(INFO, "连接断开");
                BaseConnection::ptr muduo_conn;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    std::unordered_map<muduo::net::TcpConnectionPtr, BaseConnection::ptr>::iterator it = _conns.find(conn);
                    if (it == _conns.end())
                    {
                        return;
                    }
                    muduo_conn = it->second;
                    _conns.erase(conn);
                }
                if (_cb_close)
                    _cb_close(muduo_conn);
            }
        }

        // 收到客户端消息的回调
        void onMessage(const muduo::net::TcpConnectionPtr &conn, muduo::net::Buffer *buf, muduo::Timestamp)
        {
            LOG(INFO, "连接有数据到来,开始处理");
            BaseBuffer::ptr base_buf = BufferFactory::create(buf);//将muduo库的buf封装为BaseBuff
            while (true)
            {
                if (_protocol->canProcessed(base_buf) == false)
                {
                    if (base_buf->readableSize() > maxDataSize) //防止缓冲区过多错误数据,数据过多且不能进行解析->关闭链接
                    {
                        conn->shutdown();
                        LOG(WARNING, "缓冲区中数据过大");
                        return;
                    }
                    break;
                }
                //这里能获取到一条完整消息
                BaseMessage::ptr msg;
                bool ret = _protocol->onMessage(base_buf, msg);//将缓冲区的消息构建到msg中
                if (ret == false)
                {
                    conn->shutdown();
                    LOG(WARNING, "缓冲区中数据错误");
                    return;
                }
                //消息获取成功
                BaseConnection::ptr base_conn;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    std::unordered_map<muduo::net::TcpConnectionPtr, BaseConnection::ptr>::iterator it = _conns.find(conn);
                    if (it == _conns.end())
                    {
                        conn->shutdown();
                        return;
                    }
                    base_conn = it->second;
                }
                if (_cb_message)
                    _cb_message(base_conn, msg);
            }
        }

    public:
        using ptr = std::shared_ptr<MuduoServer>;
        MuduoServer(int port) : _server(&_baseloop, muduo::net::InetAddress("0.0.0.0", port),
                                        "MuduoServer", muduo::net::TcpServer::kReusePort),
                                _protocol(ProtocolFactory::create())
        {
        }

        virtual void start() //实现start方法
        {
            _server.setConnectionCallback(std::bind(&MuduoServer::onConnection, this, std::placeholders::_1));
            _server.setMessageCallback(std::bind(&MuduoServer::onMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
            _server.start();//启动服务器
            _baseloop.loop();//开始监控
        }

    private:
        const size_t maxDataSize = (1 << 16);//缓冲区的最大值
        BaseProtocol::ptr _protocol;
        muduo::net::EventLoop _baseloop;
        muduo::net::TcpServer _server;
        std::mutex _mutex;
        std::unordered_map<muduo::net::TcpConnectionPtr, BaseConnection::ptr> _conns;//我们需要根据BaseConnection进行管理,所以需要将TcpConnectionPtr映射为BaseConnection
    };

    class ServerFactory
    {
    public:
        template <typename... Args>
        static BaseServer::ptr create(Args &&...args)
        {
            return std::make_shared<MuduoServer>(std::forward<Args>(args)...);
        }
    };

    //客户端
    class MuduoClient : public BaseClient
    {
    private:
        void onConnection(const muduo::net::TcpConnectionPtr &conn) 
        {
            if (conn->connected())
            {
                LOG(INFO,"连接建立");
                _downlatch.countDown();//计算--,为0时候唤醒阻塞
                _conn = ConnectionFactory::create(conn,_protocol); //生产出BaseConnection
            }
            else
            {
                LOG(INFO,"连接断开");
                _conn.reset();
            }
        }

        void onMessage(const muduo::net::TcpConnectionPtr &conn, muduo::net::Buffer *buf, muduo::Timestamp) 
        {
            LOG(INFO,"连接有数据到来,开始处理");
            BaseBuffer::ptr base_buf = BufferFactory::create(buf);
            while(true)
            {
                if(_protocol->canProcessed(base_buf) == false)
                {
                    if(base_buf->readableSize()>maxDataSize)
                    {
                        conn->shutdown();
                        LOG(WARNING,"缓冲区中数据过大");
                        return;
                    }
                    break;
                }
                BaseMessage::ptr msg;
                bool ret = _protocol->onMessage(base_buf,msg);
                if(ret == false)
                {
                    conn->shutdown();
                    LOG(WARNING,"缓冲区中数据错误");
                    return;
                }
                if(_cb_message) _cb_message(_conn,msg);//有回调则执行回调
            }
        }

    public:
        using ptr = std::shared_ptr<MuduoClient>;
        MuduoClient(const std::string &sip, int sport) : _protocol(ProtocolFactory::create()),
                                                         _baseloop(_loopthread.startLoop()),
                                                         _downlatch(1),
                                                         _client(_baseloop, muduo::net::InetAddress(sip, sport), "MuduoClinet")
        {
        }

        virtual void connect() override //连接服务器
        {
            LOG(INFO, "设置回调函数,连接服务器");
            _client.setConnectionCallback(std::bind(&MuduoClient::onConnection,this,std::placeholders::_1));
            _client.setMessageCallback(std::bind(&MuduoClient::onMessage,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3));
            _client.connect();
            _downlatch.wait();
            LOG(INFO,"连接服务器成功");

        }

        virtual void shutdown() override //关闭连接
        {
            return _client.disconnect();
        }

        virtual bool send(const BaseMessage::ptr &msg) override //发送消息
        {
            if(connected() == false)
            {
                LOG(WARNING,"连接已断开");
                return false;
            }
            _conn->send(msg);
            return true;
        }

        virtual BaseConnection::ptr connection() override  //获取连接对象
        {
            return _conn;
        }

        virtual bool connected() override  //判断连接是否正常
        {
            return (_conn&&_conn->connected());
        }

    private:
        const size_t maxDataSize = (1 << 16);//缓冲区最大的数量
        BaseProtocol::ptr _protocol;
        BaseConnection::ptr _conn;//封装的链接对象
        muduo::CountDownLatch _downlatch;
        muduo::net::EventLoopThread _loopthread;
        muduo::net::EventLoop *_baseloop;
        muduo::net::TcpClient _client;
    };

    class ClientFactory
    {
    public:
        template<typename ...Args>
        static BaseClient::ptr create(Args&&...args)
        {
            return std::make_shared<MuduoClient>(std::forward<Args>(args)...);
        }
    };

}
